<!DOCTYPE html>
<html lang=zh>
<head>
    <!-- so meta -->
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="HandheldFriendly" content="True">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5" />
    <meta name="description" content="在了解作用域的概念之前，我们首先来聊一聊浏览器的工作原理 浏览器的工作原理 当你打开一个浏览器之后，会经历如下过程：  向服务器请求index.html这个文件 遇到link标签后，向服务器请求获取到css文件 遇到script标签后，向服务器请求获取到js文件  浏览器的内核接着我们来简单认识一下浏览器的内核 浏览器内核称为排版引擎（layout engine），也称为浏览器引擎（browser">
<meta property="og:type" content="article">
<meta property="og:title" content="运行原理与作用域">
<meta property="og:url" content="https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/index.html">
<meta property="og:site_name" content="柯里的语法糖">
<meta property="og:description" content="在了解作用域的概念之前，我们首先来聊一聊浏览器的工作原理 浏览器的工作原理 当你打开一个浏览器之后，会经历如下过程：  向服务器请求index.html这个文件 遇到link标签后，向服务器请求获取到css文件 遇到script标签后，向服务器请求获取到js文件  浏览器的内核接着我们来简单认识一下浏览器的内核 浏览器内核称为排版引擎（layout engine），也称为浏览器引擎（browser">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://codertzm.oss-cn-chengdu.aliyuncs.com/image-20211127230129415.png">
<meta property="og:image" content="https://codertzm.oss-cn-chengdu.aliyuncs.com/image-20211127193930366.png">
<meta property="og:image" content="https://codertzm.oss-cn-chengdu.aliyuncs.com/image-20211127200540869.png">
<meta property="og:image" content="https://codertzm.oss-cn-chengdu.aliyuncs.com/image-20211127203416475.png">
<meta property="og:image" content="https://codertzm.oss-cn-chengdu.aliyuncs.com/image-20211127205657896.png">
<meta property="og:image" content="https://codertzm.oss-cn-chengdu.aliyuncs.com/image-20211127210323753.png">
<meta property="og:image" content="https://codertzm.oss-cn-chengdu.aliyuncs.com/image-20211127223451753.png">
<meta property="article:published_time" content="2021-11-09T16:00:00.000Z">
<meta property="article:modified_time" content="2022-03-05T12:31:10.768Z">
<meta property="article:author" content="柯里的语法糖">
<meta property="article:tag" content="JavaScript">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://codertzm.oss-cn-chengdu.aliyuncs.com/image-20211127230129415.png">
    
    
      
        
          <link rel="shortcut icon" href="https://codertzm.oss-cn-chengdu.aliyuncs.com/favicon.ico">
        
      
      
        
          <link rel="icon" type="image/png" href="https://codertzm.oss-cn-chengdu.aliyuncs.com/favicon.ico" sizes="192x192">
        
      
      
        
          <link rel="apple-touch-icon" sizes="180x180" href="https://codertzm.oss-cn-chengdu.aliyuncs.com/favicon.ico">
        
      
    
    <!-- title -->
    <title>运行原理与作用域</title>
    <!-- styles -->
    
<link rel="stylesheet" href="/css/style.css">

    <!-- persian styles -->
    
    <!-- rss -->
    
    
	<!-- mathjax -->
	
<meta name="generator" content="Hexo 6.0.0"></head>

<body class="max-width mx-auto px3 ltr">
    
      <div id="header-post">
  <a id="menu-icon" href="#" aria-label="Menu"><i class="fas fa-bars fa-lg"></i></a>
  <a id="menu-icon-tablet" href="#" aria-label="Menu"><i class="fas fa-bars fa-lg"></i></a>
  <a id="top-icon-tablet" href="#" aria-label="Top" onclick="$('html, body').animate({ scrollTop: 0 }, 'fast');" style="display:none;"><i class="fas fa-chevron-up fa-lg"></i></a>
  <span id="menu">
    <span id="nav">
      <ul>
        <!--
       --><li><a href="/">首页</a></li><!--
     --><!--
       --><li><a href="/tags/">标签</a></li><!--
     --><!--
       --><li><a href="/categories/">分类</a></li><!--
     --><!--
       --><li><a href="/archives/">归档</a></li><!--
     --><!--
       --><li><a target="_blank" rel="noopener" href="http://github.com/twitzz">项目</a></li><!--
     --><!--
       --><li><a href="/about/">关于</a></li><!--
     --><!--
       --><li><a href="/search/">搜索</a></li><!--
     -->
      </ul>
    </span>
    <br/>
    <span id="actions">
      <ul>
        
        <li><a class="icon" aria-label="上一篇" href="/2021/11/12/JavaScript/closure/"><i class="fas fa-chevron-left" aria-hidden="true" onmouseover="$('#i-prev').toggle();" onmouseout="$('#i-prev').toggle();"></i></a></li>
        
        
        <li><a class="icon" aria-label="下一篇" href="/2021/11/01/JavaScript/arrayLike/"><i class="fas fa-chevron-right" aria-hidden="true" onmouseover="$('#i-next').toggle();" onmouseout="$('#i-next').toggle();"></i></a></li>
        
        <li><a class="icon" aria-label="返回顶部" href="#" onclick="$('html, body').animate({ scrollTop: 0 }, 'fast');"><i class="fas fa-chevron-up" aria-hidden="true" onmouseover="$('#i-top').toggle();" onmouseout="$('#i-top').toggle();"></i></a></li>
        <li><a class="icon" aria-label="分享文章" href="#"><i class="fas fa-share-alt" aria-hidden="true" onmouseover="$('#i-share').toggle();" onmouseout="$('#i-share').toggle();" onclick="$('#share').toggle();return false;"></i></a></li>
      </ul>
      <span id="i-prev" class="info" style="display:none;">上一篇</span>
      <span id="i-next" class="info" style="display:none;">下一篇</span>
      <span id="i-top" class="info" style="display:none;">返回顶部</span>
      <span id="i-share" class="info" style="display:none;">分享文章</span>
    </span>
    <br/>
    <div id="share" style="display: none">
      <ul>
  <li><a class="icon" target="_blank" rel="noopener" href="http://www.facebook.com/sharer.php?u=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/"><i class="fab fa-facebook " aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="https://twitter.com/share?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&text=运行原理与作用域"><i class="fab fa-twitter " aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="http://www.linkedin.com/shareArticle?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&title=运行原理与作用域"><i class="fab fa-linkedin " aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="https://pinterest.com/pin/create/bookmarklet/?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&is_video=false&description=运行原理与作用域"><i class="fab fa-pinterest " aria-hidden="true"></i></a></li>
  <li><a class="icon" href="mailto:?subject=运行原理与作用域&body=Check out this article: https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/"><i class="fas fa-envelope " aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="https://getpocket.com/save?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&title=运行原理与作用域"><i class="fab fa-get-pocket " aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="http://reddit.com/submit?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&title=运行原理与作用域"><i class="fab fa-reddit " aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="http://www.stumbleupon.com/submit?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&title=运行原理与作用域"><i class="fab fa-stumbleupon " aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="http://digg.com/submit?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&title=运行原理与作用域"><i class="fab fa-digg " aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="http://www.tumblr.com/share/link?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&name=运行原理与作用域&description="><i class="fab fa-tumblr " aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="https://news.ycombinator.com/submitlink?u=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&t=运行原理与作用域"><i class="fab fa-hacker-news " aria-hidden="true"></i></a></li>
</ul>

    </div>
    <div id="toc">
      <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86"><span class="toc-number">1.</span> <span class="toc-text">浏览器的工作原理</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%84%E5%86%85%E6%A0%B8"><span class="toc-number">2.</span> <span class="toc-text">浏览器的内核</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%84%E6%B8%B2%E6%9F%93%E8%BF%87%E7%A8%8B"><span class="toc-number">3.</span> <span class="toc-text">浏览器的渲染过程</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#JavaScript%E5%BC%95%E6%93%8E"><span class="toc-number">4.</span> <span class="toc-text">JavaScript引擎</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B5%8F%E8%A7%88%E5%99%A8%E5%86%85%E6%A0%B8%E5%92%8CJavaScript%E5%BC%95%E6%93%8E%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB"><span class="toc-number">5.</span> <span class="toc-text">浏览器内核和JavaScript引擎之间的关系</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#V8%E5%BC%95%E6%93%8E"><span class="toc-number">6.</span> <span class="toc-text">V8引擎</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#JavaScript%E7%9A%84%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B"><span class="toc-number">7.</span> <span class="toc-text">JavaScript的执行过程</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%9D%E5%A7%8B%E5%8C%96%E5%85%A8%E5%B1%80%E5%AF%B9%E8%B1%A1"><span class="toc-number">7.1.</span> <span class="toc-text">初始化全局对象</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%89%A7%E8%A1%8C%E4%B8%8A%E4%B8%8B%E6%96%87%E6%A0%88"><span class="toc-number">7.2.</span> <span class="toc-text">执行上下文栈</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%81%87%E5%88%B0%E5%87%BD%E6%95%B0%E5%B0%86%E4%BC%9A%E6%80%8E%E6%A0%B7%E6%89%A7%E8%A1%8C"><span class="toc-number">7.3.</span> <span class="toc-text">遇到函数将会怎样执行</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%9C%E7%94%A8%E5%9F%9F%E7%9A%84%E7%BB%8F%E5%85%B8%E9%9D%A2%E8%AF%95%E9%A2%98"><span class="toc-number">8.</span> <span class="toc-text">作用域的经典面试题</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8F%98%E9%87%8F%E7%8E%AF%E5%A2%83%E5%92%8C%E8%AE%B0%E5%BD%95"><span class="toc-number">9.</span> <span class="toc-text">变量环境和记录</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%80%BB%E7%BB%93"><span class="toc-number">10.</span> <span class="toc-text">总结</span></a></li></ol>
    </div>
  </span>
</div>

    
    <div class="content index py4">
        
        <article class="post" itemscope itemtype="http://schema.org/BlogPosting">
  <header>
    
    <h1 class="posttitle" itemprop="name headline">
        运行原理与作用域
    </h1>



    <div class="meta">
      <span class="author" itemprop="author" itemscope itemtype="http://schema.org/Person">
        <span itemprop="name">柯里的语法糖</span>
      </span>
      
    <div class="postdate">
      
        <time datetime="2021-11-09T16:00:00.000Z" itemprop="datePublished">2021-11-10</time>
        
      
    </div>


      
    <div class="article-category">
        <i class="fas fa-archive"></i>
        <a class="category-link" href="/categories/%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/">前端基础</a>
    </div>


      
    <div class="article-tag">
        <i class="fas fa-tag"></i>
        <a class="tag-link-link" href="/tags/JavaScript/" rel="tag">JavaScript</a>
    </div>


    </div>
  </header>
  

  <div class="content" itemprop="articleBody">
    <p>在了解作用域的概念之前，我们首先来聊一聊浏览器的工作原理</p>
<h2 id="浏览器的工作原理"><a href="#浏览器的工作原理" class="headerlink" title="浏览器的工作原理"></a>浏览器的工作原理</h2><p><img src="https://codertzm.oss-cn-chengdu.aliyuncs.com/image-20211127230129415.png" alt="image-20211127230129415"></p>
<p>当你打开一个浏览器之后，会经历如下过程：</p>
<ol>
<li>向服务器请求index.html这个文件</li>
<li>遇到link标签后，向服务器请求获取到css文件</li>
<li>遇到script标签后，向服务器请求获取到js文件</li>
</ol>
<h2 id="浏览器的内核"><a href="#浏览器的内核" class="headerlink" title="浏览器的内核"></a>浏览器的内核</h2><p>接着我们来简单认识一下浏览器的内核</p>
<p>浏览器内核称为<strong>排版引擎</strong>（layout engine），也称为<strong>浏览器引擎</strong>（browser engine）、<strong>页面渲染引擎</strong>（rendering engine）</p>
<p>或<strong>样版引擎</strong>。</p>
<p>常见的浏览器内核有哪些？</p>
<ol>
<li><p>Gecko：早期被Netscape和Mozilla Firefox浏览器浏览器使用；</p>
</li>
<li><p>Trident：微软开发，被IE4~IE11浏览器使用，但是Edge浏览器已经转向Blink；</p>
</li>
<li><p>Webkit：苹果基于KHTML开发、开源的，用于Safari，Google Chrome之前也在使用；</p>
</li>
<li><p>Blink：是Webkit的一个分支，Google开发，目前应用于Google Chrome、Edge、Op</p>
</li>
</ol>
<h2 id="浏览器的渲染过程"><a href="#浏览器的渲染过程" class="headerlink" title="浏览器的渲染过程"></a>浏览器的渲染过程</h2><p>如图我们可以看到，过程大致是：浏览器内核解析html文件转换成DOM树，同时解析css文件，然后根据css规则，将他们附加在一起，生成一棵渲染树，进行layout（布局）之后进行绘制，最后展示到显示器上。</p>
<blockquote>
<p>为什么要进行layout，是因为浏览器处于不同宽度的时候的的样式是不同的，因此需要layout根据浏览器的不同状态进行布局</p>
</blockquote>
<p><img src="https://codertzm.oss-cn-chengdu.aliyuncs.com/image-20211127193930366.png" alt="image-20211127193930366"></p>
<p>你可能会说：等等，js哪去了？</p>
<p>其实，在执行浏览器渲染过程的时候，HTML解析的时候遇到了script标签后会停止解析HTML，而去加载和执行JavaScript代码。但是JavaScript代码又由谁来执行呢？答案是：<strong>JavaScript引擎</strong></p>
<h2 id="JavaScript引擎"><a href="#JavaScript引擎" class="headerlink" title="JavaScript引擎"></a>JavaScript引擎</h2><p>有其他编程语言经验的同学应该知道，高级语言都需要转换成0101的二进制代码来执行的，而JavaScript同样属于高级语言，因此对于JavaScript来说，无论是交给浏览器还是Node来执行，最终都会转换成二进制代码。</p>
<p>但是这个过程是由谁来转换的呢，其实就是JavaScript引擎</p>
<p><strong>常见的JavaScript引擎</strong>：</p>
<ol>
<li>SpiderMonkey：第一款JavaScript引擎</li>
<li>JavaScriptCore：WebKit中的JavaScript引擎，苹果公司开发</li>
<li>V8引擎：谷歌公司开发</li>
</ol>
<h2 id="浏览器内核和JavaScript引擎之间的关系"><a href="#浏览器内核和JavaScript引擎之间的关系" class="headerlink" title="浏览器内核和JavaScript引擎之间的关系"></a>浏览器内核和JavaScript引擎之间的关系</h2><ul>
<li><p>浏览器内核：负责HTML解析、布局、渲染等等相关的工作；</p>
</li>
<li><p>JavaScript引擎：解析、执行JavaScript代码；</p>
</li>
</ul>
<p>了解了这个之后我们接着来看看强大的V8引擎</p>
<h2 id="V8引擎"><a href="#V8引擎" class="headerlink" title="V8引擎"></a>V8引擎</h2><p>先来看看官方的定义</p>
<blockquote>
<p>V8是用C ++编写的Google开源高性能JavaScript和WebAssembly引擎，它用于Chrome和Node.js等。</p>
<p>它实现ECMAScript和WebAssembly，并在Windows 7或更高版本，macOS 10.12+和使用x64，IA-32， ARM或MIPS处理器的Linux系统上运行。</p>
<p>V8可以独立运行，也可以嵌入到任何C ++应用程序中</p>
</blockquote>
<p>下面这张图是V8引擎的执行原理图</p>
<p><img src="https://codertzm.oss-cn-chengdu.aliyuncs.com/image-20211127200540869.png" alt="image-20211127200540869"></p>
<p>V8引擎大概会做如下的事情</p>
<ol>
<li>Blink（浏览器内核的一种）把js下载下来，将js代码交给V8引擎，</li>
<li>Steam模块获取到代码后进行编码转换，交给Scanner</li>
<li>Scanner会进行<strong>词法分析</strong>，将代码转换成tokens<ul>
<li>比如 <code>const name = &#39;curry&#39;</code> ，生成的tokens就会将这些信息分析成：<code>tokens:[&#123;type:&#39;keyword&#39;,value:&#39;const&#39;&#125;,&#123;type:&#39;identifier&#39;,value:&#39;name&#39;&#125;]</code></li>
</ul>
</li>
<li>tokens经过PreParser和Parser后转换成AST抽象语法树<strong>（语法分析）</strong><ul>
<li>其中Parser就是直接将tokens转换成AST树</li>
<li>PreParser称为<strong>预解析</strong>，为什么需要预解析，是因为并不是所有js代码都会在一开始被执行，如果直接对所有的js代码进行解析，必然会影响网页的运行效率，所以V8引擎实现了<strong>延迟解析（Lazy-Parsing）</strong>的方案，只解析暂时需要的内容，而对函数的全部解析是在<strong>函数被调用的时候才会进行</strong></li>
<li>比如一个outer函数里面有一个inner函数，此时这个inner函数就会被预解析</li>
</ul>
</li>
<li>生成AST树后，会被一个叫<strong>Ignition</strong>的模块转换成字节码，然后就是代码的执行过程了</li>
<li>V8引擎内部还有一个叫做<strong>TurboFan</strong>的编译器，可以将字节码编译为CPU可以直接运行的机器码<ol>
<li>如果一个函数被多次调用就会被标记为<strong>热点函数</strong>，那么就会经过TurboFan编译为优化的机器码，提高代码的运行效率</li>
<li>但是机器码也会被转换为字节码，这是因为如果一个函数的参数的<strong>类型发生了变化</strong>，之前的机器码就不能正确运算，就会被逆向转换成为字节码</li>
</ol>
</li>
</ol>
<h2 id="JavaScript的执行过程"><a href="#JavaScript的执行过程" class="headerlink" title="JavaScript的执行过程"></a>JavaScript的执行过程</h2><p>通过下面这个例子，我们来把JavaScript的执行过程弄清楚，别急，只有弄清楚了JavaScript的执行原理，才能从根本上弄懂作用域</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> age = <span class="number">123</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(age)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> num1 = <span class="number">1</span></span><br><span class="line"><span class="keyword">var</span> num2 = <span class="number">1</span></span><br><span class="line"><span class="keyword">var</span> result = num1 + num2</span><br><span class="line"><span class="built_in">console</span>.log(result)</span><br><span class="line"></span><br><span class="line">foo()</span><br></pre></td></tr></table></figure>

<h3 id="初始化全局对象"><a href="#初始化全局对象" class="headerlink" title="初始化全局对象"></a>初始化全局对象</h3><p>js引擎在执行代码前，会在堆内存中创建一个全局对象：GlobalObject（后面统称为GO）</p>
<p>该对象在所有的作用域中都可以访问到，里面存在JavaScript的内置函数，比如Date、Array、setTimeout等</p>
<p>其中还有一个<strong>window属性</strong>指向GO对象自己</p>
<p><img src="https://codertzm.oss-cn-chengdu.aliyuncs.com/image-20211127203416475.png" alt="image-20211127203416475"></p>
<h3 id="执行上下文栈"><a href="#执行上下文栈" class="headerlink" title="执行上下文栈"></a>执行上下文栈</h3><p>V8为了执行代码会创建一个叫<strong>执行上下文栈（Execution Context Stack，简称ECS）</strong>，它是用于执行<strong>代码的调用栈</strong></p>
<p>我们一开始执行的是全局的代码，因此为了让全局代码能够顺利执行，需要创建<strong>全局执行上下文（Global Execution Context，简称GEC）</strong></p>
<p>创建完GEC后会被放入到ESC中，</p>
<p>此时GEC会包含两部分内容：VO（variable object）和需要执行的代码，（其中VO指向GO）。</p>
<p>执行代码前，在经过parser被转换成AST的过程中，会将定义的全局变量和函数加入到GO中，但并不会赋值，这就是<strong>变量提升</strong></p>
<p><img src="https://codertzm.oss-cn-chengdu.aliyuncs.com/image-20211127205657896.png" alt="image-20211127205657896"></p>
<p>之后再一步步执行代码，进行赋值操作，此时有函数的话，将会在堆内存中为函数对象（FunctionObject）开辟一段空间，然后让GO中的函数的变量指向函数对象的内存地址。</p>
<p><img src="https://codertzm.oss-cn-chengdu.aliyuncs.com/image-20211127210323753.png" alt="image-20211127210323753"></p>
<h3 id="遇到函数将会怎样执行"><a href="#遇到函数将会怎样执行" class="headerlink" title="遇到函数将会怎样执行"></a>遇到函数将会怎样执行</h3><p>在执行过程中遇到一个函数的时候，会根据函数体创建一个函数执行上下文（Functional Execution Context，后面统称为FEC），压入到ECS中</p>
<p><strong>FEC包含三部分</strong>：</p>
<ol>
<li>解析函数成为AST时，会创建一个Activation Object（AO）对象，AO对象中包含形参、arguments、函数定义和指向函数对象、定义的变量</li>
<li>作用域链：由VO（在函数中也就是AO）和父级的VO组成，查找时会一层层往上找，这就是<strong>作用域链的查找方式</strong>，因此这也说明，作用域链是在解析的时候就已经确定了</li>
<li>this绑定的值：执行时绑定</li>
</ol>
<p><img src="https://codertzm.oss-cn-chengdu.aliyuncs.com/image-20211127223451753.png"></p>
<h2 id="作用域的经典面试题"><a href="#作用域的经典面试题" class="headerlink" title="作用域的经典面试题"></a>作用域的经典面试题</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> n = <span class="number">100</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo1</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(n) <span class="comment">// ?</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo2</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">var</span> n = <span class="number">200</span></span><br><span class="line">    <span class="built_in">console</span>.log(n) </span><br><span class="line">    foo1()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">foo2()</span><br><span class="line"><span class="built_in">console</span>.log(n)</span><br></pre></td></tr></table></figure>

<p>仔细分析后，我们可以明确得出其他两个n的值，但是有注释的那一行的输出究竟是什么</p>
<p>当foo2（）调用后，会创建一个函数执行上下文，里面的VO指向<strong>foo2的AO对象</strong>，此时foo2的作用域链应该是<strong>VO+GO</strong>，然后调用foo1。</p>
<p>此时foo1（）会创建一个函数执行上下文，里面的VO指向<strong>foo1的AO对象</strong>，此时foo1的作用域链应该是<strong>VO+GO</strong>。</p>
<p>因此当它去查找n这个变量的时候，没有从VO中找到n，就会去parent scope也就是GO中查找n这个变量，进而输出100这个值</p>
<h2 id="变量环境和记录"><a href="#变量环境和记录" class="headerlink" title="变量环境和记录"></a>变量环境和记录</h2><p>最后我们再来聊一聊变量环境和记录</p>
<p>实际上在最新的ECMA规范中，它对一些词汇进行了修改</p>
<p>来对比一下早期的ECMA规范和最新的ECMA规范</p>
<p>早期的：</p>
<blockquote>
<p>每一个执行上下文会被关联到一个变量环境（<strong>variable Object</strong>）中，在源代码中的变量和函数的声明会被作为<strong>属性</strong>添加到VO中。</p>
<p>对于函数来说，参数也会被添加到VO中。</p>
</blockquote>
<p>最新的：</p>
<blockquote>
<p>每一个执行上下文会关联到一个变量环境（<strong>variable Environment</strong>），在执行代码中变量和函数的声明会作为<strong>环境记录</strong>（Environment Record）添加到变量环境中。</p>
<p>对于函数来说，参数也会被作为环境记录添加到变量环境中。</p>
</blockquote>
<p>通过这个变化我们可以知道，在最新的规范中，VO对象已经被叫做了VE对象，而变量和函数的声明原来被称为属性现在被称为了环境记录</p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>通过认识浏览器和V8引擎，我们一步步了解了JavaScript的运行原理，从而理解了作用域链到底是怎么查找的，以及作用域链其实是在解析的时候就已经确定了，与函数的调用位置无关。最后通过面试题，加深了作用域的理解，相信看完这篇文章，不管遇到什么样的关于作用域链的面试题都能轻松搞定。</p>

  </div>
</article>



        
          <div id="footer-post-container">
  <div id="footer-post">

    <div id="nav-footer" style="display: none">
      <ul>
         
          <li><a href="/">首页</a></li>
         
          <li><a href="/tags/">标签</a></li>
         
          <li><a href="/categories/">分类</a></li>
         
          <li><a href="/archives/">归档</a></li>
         
          <li><a target="_blank" rel="noopener" href="http://github.com/twitzz">项目</a></li>
         
          <li><a href="/about/">关于</a></li>
         
          <li><a href="/search/">搜索</a></li>
        
      </ul>
    </div>

    <div id="toc-footer" style="display: none">
      <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86"><span class="toc-number">1.</span> <span class="toc-text">浏览器的工作原理</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%84%E5%86%85%E6%A0%B8"><span class="toc-number">2.</span> <span class="toc-text">浏览器的内核</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%84%E6%B8%B2%E6%9F%93%E8%BF%87%E7%A8%8B"><span class="toc-number">3.</span> <span class="toc-text">浏览器的渲染过程</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#JavaScript%E5%BC%95%E6%93%8E"><span class="toc-number">4.</span> <span class="toc-text">JavaScript引擎</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B5%8F%E8%A7%88%E5%99%A8%E5%86%85%E6%A0%B8%E5%92%8CJavaScript%E5%BC%95%E6%93%8E%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB"><span class="toc-number">5.</span> <span class="toc-text">浏览器内核和JavaScript引擎之间的关系</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#V8%E5%BC%95%E6%93%8E"><span class="toc-number">6.</span> <span class="toc-text">V8引擎</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#JavaScript%E7%9A%84%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B"><span class="toc-number">7.</span> <span class="toc-text">JavaScript的执行过程</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%9D%E5%A7%8B%E5%8C%96%E5%85%A8%E5%B1%80%E5%AF%B9%E8%B1%A1"><span class="toc-number">7.1.</span> <span class="toc-text">初始化全局对象</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%89%A7%E8%A1%8C%E4%B8%8A%E4%B8%8B%E6%96%87%E6%A0%88"><span class="toc-number">7.2.</span> <span class="toc-text">执行上下文栈</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%81%87%E5%88%B0%E5%87%BD%E6%95%B0%E5%B0%86%E4%BC%9A%E6%80%8E%E6%A0%B7%E6%89%A7%E8%A1%8C"><span class="toc-number">7.3.</span> <span class="toc-text">遇到函数将会怎样执行</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%9C%E7%94%A8%E5%9F%9F%E7%9A%84%E7%BB%8F%E5%85%B8%E9%9D%A2%E8%AF%95%E9%A2%98"><span class="toc-number">8.</span> <span class="toc-text">作用域的经典面试题</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8F%98%E9%87%8F%E7%8E%AF%E5%A2%83%E5%92%8C%E8%AE%B0%E5%BD%95"><span class="toc-number">9.</span> <span class="toc-text">变量环境和记录</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%80%BB%E7%BB%93"><span class="toc-number">10.</span> <span class="toc-text">总结</span></a></li></ol>
    </div>

    <div id="share-footer" style="display: none">
      <ul>
  <li><a class="icon" target="_blank" rel="noopener" href="http://www.facebook.com/sharer.php?u=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/"><i class="fab fa-facebook fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="https://twitter.com/share?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&text=运行原理与作用域"><i class="fab fa-twitter fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="http://www.linkedin.com/shareArticle?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&title=运行原理与作用域"><i class="fab fa-linkedin fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="https://pinterest.com/pin/create/bookmarklet/?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&is_video=false&description=运行原理与作用域"><i class="fab fa-pinterest fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" href="mailto:?subject=运行原理与作用域&body=Check out this article: https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/"><i class="fas fa-envelope fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="https://getpocket.com/save?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&title=运行原理与作用域"><i class="fab fa-get-pocket fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="http://reddit.com/submit?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&title=运行原理与作用域"><i class="fab fa-reddit fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="http://www.stumbleupon.com/submit?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&title=运行原理与作用域"><i class="fab fa-stumbleupon fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="http://digg.com/submit?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&title=运行原理与作用域"><i class="fab fa-digg fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="http://www.tumblr.com/share/link?url=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&name=运行原理与作用域&description="><i class="fab fa-tumblr fa-lg" aria-hidden="true"></i></a></li>
  <li><a class="icon" target="_blank" rel="noopener" href="https://news.ycombinator.com/submitlink?u=https://danyuan30.gitee.io/2021/11/10/JavaScript/scope/&t=运行原理与作用域"><i class="fab fa-hacker-news fa-lg" aria-hidden="true"></i></a></li>
</ul>

    </div>

    <div id="actions-footer">
        <a id="menu" class="icon" href="#" onclick="$('#nav-footer').toggle();return false;"><i class="fas fa-bars fa-lg" aria-hidden="true"></i> 菜单</a>
        <a id="toc" class="icon" href="#" onclick="$('#toc-footer').toggle();return false;"><i class="fas fa-list fa-lg" aria-hidden="true"></i> 目录</a>
        <a id="share" class="icon" href="#" onclick="$('#share-footer').toggle();return false;"><i class="fas fa-share-alt fa-lg" aria-hidden="true"></i> 分享</a>
        <a id="top" style="display:none" class="icon" href="#" onclick="$('html, body').animate({ scrollTop: 0 }, 'fast');"><i class="fas fa-chevron-up fa-lg" aria-hidden="true"></i> 返回顶部</a>
    </div>

  </div>
</div>

        
        <footer id="footer">
  <div class="footer-left">
    Copyright &copy;
    
    
    2021-2022
    柯里的语法糖
  </div>
  <div class="footer-right">
    <nav>
      <ul>
        <!--
       --><li><a href="/">首页</a></li><!--
     --><!--
       --><li><a href="/tags/">标签</a></li><!--
     --><!--
       --><li><a href="/categories/">分类</a></li><!--
     --><!--
       --><li><a href="/archives/">归档</a></li><!--
     --><!--
       --><li><a target="_blank" rel="noopener" href="http://github.com/twitzz">项目</a></li><!--
     --><!--
       --><li><a href="/about/">关于</a></li><!--
     --><!--
       --><li><a href="/search/">搜索</a></li><!--
     -->
      </ul>
    </nav>
  </div>
</footer>

    </div>
    <!-- styles -->



  <link rel="preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" crossorigin="anonymous" onload="this.onload=null;this.rel='stylesheet'"/>


    <!-- jquery -->
 
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" crossorigin="anonymous"></script> 




<!-- clipboard -->

  
    <script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.7/clipboard.min.js" crossorigin="anonymous"></script> 
  
  <script type="text/javascript">
  $(function() {
    // copy-btn HTML
    var btn = "<span class=\"btn-copy tooltipped tooltipped-sw\" aria-label=\"复制到粘贴板!\">";
    btn += '<i class="far fa-clone"></i>';
    btn += '</span>'; 
    // mount it!
    $(".highlight table").before(btn);
    var clip = new ClipboardJS('.btn-copy', {
      text: function(trigger) {
        return Array.from(trigger.nextElementSibling.querySelectorAll('.code')).reduce((str,it)=>str+it.innerText+'\n','')
      }
    });
    clip.on('success', function(e) {
      e.trigger.setAttribute('aria-label', "复制成功!");
      e.clearSelection();
    })
  })
  </script>


<script src="/js/main.js"></script>

<!-- search -->

<!-- Google Analytics -->

<!-- Baidu Analytics -->

<!-- Cloudflare Analytics -->

<!-- Umami Analytics -->

<!-- Disqus Comments -->

<!-- utterances Comments -->

</body>
</html>
